﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

namespace A1
{


    class AI : Paddle
    {

        int gameWidth;
        int gameHeight;


        /// <summary>
        /// Constructor for the automated paddles.
        /// </summary>
        /// <param name="s">Sprite the file will use, horizontal or vertical.</param>
        /// <param name="l">Lets the AI methods know which side it should consider things from.</param>
        /// <param name="b">Ball the game's using.</param>
        /// <param name="width">Width of the game window.</param>
        /// <param name="height">Height of the game window.</param>
        /// <param name="d">Difficulty of the AI opponent.</param>
        public AI(Texture2D s, Game1.Position l, Ball b, int width, int height, Game1.Difficulty d, GameTime gameTime)
            : base(s, b, l, height, width, gameTime)
        {
            position = l; gameWidth = width; gameHeight = height;



            difficulty = d;
        }

        /// <summary>
        /// This method is used by others to guess where the ball will land,
        /// it is important for hard mode, which makes it hard. They go where
        /// the ball is going, not where it is!
        /// </summary>
        /// <returns>Int estimating the ball's landing location, relative to position of paddle.</returns>
        private int DetermineBallLanding()
        {
            switch (position)
            {
                case Game1.Position.Left:
                    {
                        if (ball.SpeedX < 0)
                        {
                            int time = (ball.Rec.X - rec.X) / ((int)ball.SpeedX);

                            if (time < 0)
                            { time = time * -1; }

                            int b_y = ball.Rec.Y;
                            int b_s = (int)ball.SpeedY;

                            for (int i = 0; i < time; i++)
                            {
                                b_y += b_s;
                                if (b_y > gameHeight - 30)
                                { b_s *= -1; }
                                else if (b_y < 30)
                                { b_s *= -1; }
                            }


                            return b_y;
                        }
                        else
                            return (gameHeight / 2);
                    }
                case Game1.Position.Top:
                    {
                        if (ball.SpeedY < 0)
                        {
                            int time = (rec.Y - ball.Rec.Y) / ((int)ball.SpeedY);

                            if (time < 0)
                            { time = time * -1; }

                            int b_x = ball.Rec.X;
                            int b_s = (int)ball.SpeedX;

                            for (int i = 0; i < time; i++)
                            {
                                b_x += b_s;
                                if (b_x > (gameWidth - 30))
                                { b_s *= -1; }
                                else if (b_x < 30)
                                { b_s *= -1; }
                            }


                            return b_x;
                        }
                        else
                            return (gameWidth / 2);

                    }
                case Game1.Position.Bottom:
                    {
                        if (ball.SpeedY > 0)
                        {
                            int time = (rec.Y - ball.Rec.Y) / ((int)ball.SpeedY);

                            if (time < 0)
                            { time = time * -1; }

                            int b_x = ball.Rec.X;
                            int b_s = (int)ball.SpeedX;

                            for (int i = 0; i < time; i++)
                            {
                                b_x += b_s;
                                if (b_x > (gameWidth - 30))
                                { b_s *= -1; }
                                else if (b_x < 30)
                                { b_s *= -1; }
                            }


                            return b_x;
                        }
                        else
                        { return gameWidth / 2; }
                    }

                case Game1.Position.Right:
                    {
                        if (ball.SpeedX > 0)
                        {
                            int time = (rec.X - ball.Rec.X) / ((int)ball.SpeedX);

                            if (time < 0)
                            { time = time * -1; }

                            int b_y = ball.Rec.Y;
                            int b_s = (int)ball.SpeedY;

                            for (int i = 0; i < time; i++)
                            {
                                b_y += b_s;
                                if (b_y > gameHeight - 30)
                                { b_s *= -1; }
                                else if (b_y < 30)
                                { b_s *= -1; }
                            }


                            return b_y;
                        }
                        else
                            return (gameHeight / 2);

                    }
                default:
                    if (ball.SpeedX > 0)
                    {
                        int time = (rec.X - ball.Rec.X) / ((int)ball.SpeedX);

                        if (time < 0)
                        { time = time * -1; }

                        int b_y = ball.Rec.Y;
                        int b_s = (int)ball.SpeedY;

                        for (int i = 0; i < time; i++)
                        {
                            b_y += b_s;
                            if (b_y > gameHeight - 30)
                            { b_s *= -1; }
                            else if (b_y < 30)
                            { b_s *= -1; }
                        }


                        return b_y;
                    }
                    else
                        return (gameHeight / 2);

            }
        }

        /// <summary>
        /// Simply a switch to determine which move methods
        /// the AI has to use.
        /// </summary>
        public void AIControl()
        {
            switch (position)
            {
                case Game1.Position.Left:
                    LeftPosition();
                    break;
                case Game1.Position.Top:
                    TopPosition();
                    break;
                case Game1.Position.Bottom:
                    BottomPosition();
                    break;
                case Game1.Position.Right:
                    RightPosition();
                    break;
                default:
                    LeftPosition();
                    break;
            }
        }


        /// <summary>
        /// Provides the 'bounce' for the ball.
        /// </summary>
        public void AICollision()
        {
            if (rec.Intersects(ball.Rec))
            {
                switch (position)
                {
                    case Game1.Position.Left:
                        if (rec.Intersects(ball.Rec) && rec.X == 30)
                        {
                            ball.LastHit = this;
                            ball.SpeedX = ball.SpeedX * -1;
                            if (ball.SpeedX < 16)
                            { ball.SpeedX++; }
                        }
                        else if (rec.Intersects(ball.Rec) && rec.X > 30)
                        {
                            ball.LastHit = this;
                            ball.SpeedX = ball.SpeedX * -1;
                            if (rec.X + rec.Width / 2 > ball.Rec.X)
                            { ball.SpeedY = 15; }
                            else if (rec.X + rec.Width / 2 < ball.Rec.X)
                            { ball.SpeedY = -15; }
                        }
                        break;

                    case Game1.Position.Top:
                        if (rec.Intersects(ball.Rec) && rec.Y == 30)
                        {
                            ball.LastHit = this;
                            ball.SpeedY = ball.SpeedY * -1;
                            if (ball.SpeedY < 16)
                            { ball.SpeedY++; }
                        }
                        else if (rec.Intersects(ball.Rec) && rec.Y > 30)
                        {
                            ball.LastHit = this;
                            ball.SpeedY = ball.SpeedY * -1;
                            if (rec.Y + rec.Height / 2 > ball.Rec.Y)
                            { ball.SpeedX = 15; }
                            else if (rec.Y + rec.Height / 2 < ball.Rec.Y)
                            { ball.SpeedX = -15; }
                        }
                        break;
                    case Game1.Position.Bottom:
                        if (rec.Intersects(ball.Rec) && rec.Y == gameHeight - 30)
                        {
                            ball.LastHit = this;
                            ball.SpeedY = ball.SpeedY * -1;
                            if (ball.SpeedY > -16)
                            { ball.SpeedY--; }
                        }
                        else if (rec.Intersects(ball.Rec) && rec.Y < gameHeight - 30)
                        {
                            ball.LastHit = this;
                            ball.SpeedY = ball.SpeedY * -1;
                            if (rec.Y + rec.Height / 2 > ball.Rec.Y)
                            { ball.SpeedX = 15; }
                            else if (rec.Y + rec.Height / 2 < ball.Rec.Y)
                            { ball.SpeedX = -15; }
                        }
                        break;
                    case Game1.Position.Right:
                        if (rec.Intersects(ball.Rec) && rec.X == gameWidth - 30)
                        {
                            ball.LastHit = this;
                            ball.SpeedX = ball.SpeedX * -1;
                            if (ball.SpeedX > -16)
                                ball.SpeedX--;
                        }
                        else if (rec.Intersects(ball.Rec) && rec.X < gameWidth - 30)
                        {
                            ball.LastHit = this;
                            ball.SpeedX = ball.SpeedX * -1;
                            if (rec.X + rec.Width / 2 > ball.Rec.X)
                            { ball.SpeedY = 15; }
                            else if (rec.X + rec.Width / 2 < ball.Rec.X)
                            { ball.SpeedY = -15; }
                        }
                        break;
                    default: //Left Side
                        if (rec.Intersects(ball.Rec) && rec.X == 30)
                        {
                            ball.LastHit = this;
                            ball.SpeedX = ball.SpeedX * -1;
                            if (ball.SpeedX < 16)
                            { ball.SpeedX++; }
                        }
                        else if (rec.Intersects(ball.Rec) && rec.X > 30)
                        {
                            ball.LastHit = this;
                            ball.SpeedX = ball.SpeedX * -1;
                            if (rec.X + rec.Width / 2 > ball.Rec.X)
                            { ball.SpeedY = 15; }
                            else if (rec.X + rec.Width / 2 < ball.Rec.X)
                            { ball.SpeedY = -15; }
                        }
                        break;
                }
            }
        }

        /// <summary>
        /// Update method, checks to see if the paddle has been disabled, for Elimination mode
        /// if it has it will be turned into, functionally, a wall. Collision will still run.
        /// </summary>
        /// <param name="gameTime"></param>
        public override void Update(GameTime gameTime)
        {
            if (!disabled)
            {
                if (ball.FourPlayer == true && ball.Charge != true)
                {
                    if ((ball.LeftScore == 0 && position == Game1.Position.Left) ||
                        (ball.RightScore == 0 && position == Game1.Position.Right) ||
                        (ball.TopScore == 0 && position == Game1.Position.Top) ||
                        (ball.BottomScore == 0 && position == Game1.Position.Bottom))
                    {
                        disabled = true;
                        switch (position)
                        {
                            case Game1.Position.Left:
                                {
                                    rec.Height = gameHeight; rec.Y = 0;
                                    break;
                                }
                            case Game1.Position.Right:
                                {
                                    rec.Height = gameHeight; rec.Y = 0;
                                    break;
                                }
                            case Game1.Position.Top:
                                {
                                    rec.Width = gameWidth; rec.X = 0;
                                    break;
                                }
                            case Game1.Position.Bottom:
                                {
                                    rec.Width = gameWidth; rec.X = 0;
                                    break;
                                }
                        }
                    }
                }
                AIControl();

                PowerCountdown(gameTime);
                ApplyPower();
            }
            AICollision();
        }

        /// <summary>
        /// The movement methods for an AI on the left, different by
        /// difficulty. Easy mode is slow and simply chases the ball,
        /// Medium mode chases the ball but goes faster.
        /// Hard mode is more interesting, also...well, hard,
        /// because while it's only as fast as easy it judges where the ball's
        /// going and goes there rather than following after it.
        /// </summary>
        private void LeftPosition()
        {
            switch (difficulty)
            {
                case Game1.Difficulty.Easy:
                    if (rec.Y > ball.Rec.Y)
                    {
                        rec.Y = rec.Y - 7;
                        if (rec.Y < ball.Rec.Y)
                        { rec.Y = ball.Rec.Y; }
                    }
                    else if (rec.Y < ball.Rec.Y)
                    {
                        rec.Y = rec.Y + 7;
                        if (rec.Y > ball.Rec.Y)
                        { rec.Y = ball.Rec.Y; }
                    }

                    if (ball.Rec.Y > rec.Y && ball.Rec.Y < rec.Y + rec.Height
                        && ball.Rec.X - rec.X <= chargeDistance)
                    { /*Charge();*/ }
                    break;

                case Game1.Difficulty.Medium:
                    if (rec.Y + (rec.Height / 2) > ball.Rec.Y)
                    {
                        rec.Y = rec.Y - 10;
                        if (rec.Y + (rec.Height / 2) < ball.Rec.Y)
                        { rec.Y = ball.Rec.Y - (rec.Height / 2); }
                    }
                    else if (rec.Y + (rec.Height / 2) < ball.Rec.Y)
                    {
                        rec.Y = rec.Y + 10;
                        if (rec.Y + (rec.Height / 2) > ball.Rec.Y)
                        { rec.Y = ball.Rec.Y - (rec.Height / 2); }
                    }
                    if (DetermineBallLanding() > rec.Y && DetermineBallLanding() < rec.Y + rec.Height
                        && ball.Rec.X - rec.X <= chargeDistance)
                    { /*Charge();*/ }
                    break;

                case Game1.Difficulty.Hard:
                    if (rec.Y + (rec.Height / 2) > DetermineBallLanding())
                    {
                        rec.Y = rec.Y - 7;
                        if (rec.Y + (rec.Height / 2) < DetermineBallLanding())
                        { rec.Y = DetermineBallLanding() - (rec.Height / 2); }
                    }
                    else if (rec.Y + (rec.Height / 2) < DetermineBallLanding())
                    {
                        rec.Y = rec.Y + 7;
                        if (rec.Y + (rec.Height / 2) > DetermineBallLanding())
                        { rec.Y = DetermineBallLanding() - (rec.Height / 2); }
                    }
                    if (ball.Rec.Y > rec.Y && ball.Rec.Y < rec.Y + rec.Height
                        && ball.Rec.X - rec.X <= chargeDistance)
                    { /*Charge();*/ }
                    break;
            }
        }

        /// <summary>
        /// As with LeftPosition() commentary, but for the Right side.
        /// </summary>
        private void RightPosition()
        {
            switch (difficulty)
            {
                case Game1.Difficulty.Easy:
                    if (rec.Y > ball.Rec.Y)
                    {
                        rec.Y = rec.Y - 7;
                        if (rec.Y < ball.Rec.Y)
                        { rec.Y = ball.Rec.Y; }
                    }
                    else if (rec.Y < ball.Rec.Y)
                    {
                        rec.Y = rec.Y + 7;
                        if (rec.Y > ball.Rec.Y)
                        { rec.Y = ball.Rec.Y; }
                    }
                    if (ball.Rec.Y > rec.Y && ball.Rec.Y < rec.Y + rec.Height
                        && rec.X - ball.Rec.X <= chargeDistance)
                    { /*Charge();*/ }
                    break;

                case Game1.Difficulty.Medium:
                    if (rec.Y + (rec.Height / 2) > ball.Rec.Y)
                    {
                        rec.Y = rec.Y - 7;
                        if (rec.Y + (rec.Height / 2) < ball.Rec.Y)
                        { rec.Y = ball.Rec.Y - (rec.Height / 2); }
                    }
                    else if (rec.Y + (rec.Height / 2) < ball.Rec.Y)
                    {
                        rec.Y = rec.Y + 7;
                        if (rec.Y + (rec.Height / 2) > ball.Rec.Y)
                        { rec.Y = ball.Rec.Y - (rec.Height / 2); }
                    }
                    if (ball.Rec.Y > rec.Y && ball.Rec.Y < rec.Y + rec.Height
                        && rec.X - ball.Rec.X <= chargeDistance)
                    { /*Charge();*/}
                    break;

                case Game1.Difficulty.Hard:
                    if (rec.Y + (rec.Height / 2) > DetermineBallLanding())
                    {
                        rec.Y = rec.Y - 7;
                        if (rec.Y + (rec.Height / 2) < DetermineBallLanding())
                        { rec.Y = DetermineBallLanding() - (rec.Height / 2); }
                    }
                    else if (rec.Y + (rec.Height / 2) < DetermineBallLanding())
                    {
                        rec.Y = rec.Y + 7;
                        if (rec.Y + (rec.Height / 2) > DetermineBallLanding())
                        { rec.Y = DetermineBallLanding() - (rec.Height / 2); }
                    }
                    if (ball.Rec.Y > rec.Y && ball.Rec.Y < rec.Y + rec.Height
                        && rec.X - ball.Rec.X <= chargeDistance)
                    { /*Charge();*/}
                    break;
            }
        }

        /// <summary>
        /// As with LeftPosition() commentary, but for the Top side.
        /// </summary>
        private void TopPosition()
        {
            switch (difficulty)
            {
                case Game1.Difficulty.Easy:
                    if (rec.X > ball.Rec.X)
                    {
                        rec.X = rec.X - 7;
                        if (rec.X < ball.Rec.X)
                        { rec.X = ball.Rec.X; }
                    }
                    else if (rec.X < ball.Rec.X)
                    {
                        rec.X = rec.X + 7;
                        if (rec.X > ball.Rec.X)
                        { rec.X = ball.Rec.X; }
                    }
                    if (ball.Rec.X > rec.X && ball.Rec.X < rec.X + rec.Width
                        && ball.Rec.Y - rec.Y <= chargeDistance)
                    { /*Charge();*/}
                    break;

                case Game1.Difficulty.Medium:
                    if (rec.X + (rec.Width / 2) > ball.Rec.X)
                    {
                        rec.X = rec.X - 7;
                        if (rec.X + (rec.Width / 2) < ball.Rec.X)
                        { rec.X = ball.Rec.X - (rec.Width / 2); }
                    }
                    else if (rec.X + (rec.Width / 2) < ball.Rec.X)
                    {
                        rec.X = rec.X + 7;
                        if (rec.X + (rec.Width / 2) > ball.Rec.X)
                        { rec.X = ball.Rec.X - (rec.Width / 2); }
                    }
                    if (ball.Rec.X > rec.X && ball.Rec.X < rec.X + rec.Width
                        && ball.Rec.Y - rec.Y <= chargeDistance)
                    { /*Charge();*/}
                    break;

                case Game1.Difficulty.Hard:
                    if (rec.X + (rec.Width / 2) > DetermineBallLanding())
                    {
                        rec.X = rec.X - 7;
                        if (rec.X + (rec.Width / 2) < DetermineBallLanding())
                        { rec.X = DetermineBallLanding() - (rec.Width / 2); }
                    }
                    else if (rec.X + (rec.Width / 2) < DetermineBallLanding())
                    {
                        rec.X = rec.X + 7;
                        if (rec.X + (rec.Width / 2) > DetermineBallLanding())
                        { rec.X = DetermineBallLanding() - (rec.Width / 2); }
                    }
                    if (ball.Rec.X > rec.X && ball.Rec.X < rec.X + rec.Width
                        && ball.Rec.Y - rec.Y <= chargeDistance)
                    { /*Charge();*/}
                    break;
            }
        }

        /// <summary>
        /// As with LeftPosition() commentary, but for the Bottom side.
        /// </summary>
        private void BottomPosition()
        {
            switch (difficulty)
            {
                case Game1.Difficulty.Easy:
                    if (rec.X > ball.Rec.X)
                    {
                        rec.X = rec.X - 7;
                        if (rec.X < ball.Rec.X)
                        { rec.X = ball.Rec.X; }
                    }
                    else if (rec.X < ball.Rec.X)
                    {
                        rec.X = rec.X + 7;
                        if (rec.X > ball.Rec.X)
                        { rec.X = ball.Rec.X; }
                    }
                    if (ball.Rec.X > rec.X && ball.Rec.X < rec.X + rec.Width
                        && rec.Y - ball.Rec.Y <= chargeDistance)
                    { /*Charge();*/}
                    break;

                case Game1.Difficulty.Medium:
                    if (rec.X + (rec.Width / 2) > ball.Rec.X)
                    {
                        rec.X = rec.X - 7;
                        if (rec.X + (rec.Width / 2) < ball.Rec.X)
                        { rec.X = ball.Rec.X - (rec.Width / 2); }
                    }
                    else if (rec.X + (rec.Width / 2) < ball.Rec.X)
                    {
                        rec.X = rec.X + 7;
                        if (rec.X + (rec.Width / 2) > ball.Rec.X)
                        { rec.X = ball.Rec.X - (rec.Width / 2); }
                    }
                    if (ball.Rec.X > rec.X && ball.Rec.X < rec.X + rec.Width
                        && rec.Y - ball.Rec.Y <= chargeDistance)
                    { /*Charge();*/}
                    break;

                case Game1.Difficulty.Hard:
                    if (rec.X + (rec.Width / 2) > DetermineBallLanding())
                    {
                        rec.X = rec.X - 7;
                        if (rec.X + (rec.Width / 2) < DetermineBallLanding())
                        { rec.X = DetermineBallLanding() - (rec.Width / 2); }
                    }
                    else if (rec.X + (rec.Width / 2) < DetermineBallLanding())
                    {
                        rec.X = rec.X + 7;
                        if (rec.X + (rec.Width / 2) > DetermineBallLanding())
                        { rec.X = DetermineBallLanding() - (rec.Width / 2); }
                    }
                    if (ball.Rec.X > rec.X && ball.Rec.X < rec.X + rec.Width
                        && rec.Y - ball.Rec.Y <= chargeDistance)
                    { /*Charge();*/}
                    break;
            }


        }
    }
}
